package com.scs.application.modules.sys.schedule;

import com.scs.application.consts.GlobalConsts;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.utils.DateUtils;
import com.scs.application.core.utils.SpringUtils;
import com.scs.application.core.utils.UtilCommon;
import com.scs.application.core.utils.UtilJavax;
import com.scs.application.modules.base.util.CommonService;
import com.scs.application.modules.sys.entity.Log;
import com.scs.application.modules.sys.entity.ScheduleJob;
import com.scs.application.modules.sys.enums.LogType;
import com.scs.application.modules.sys.model.RestResult;
import com.scs.application.modules.sys.service.LogService;
import com.scs.application.modules.sys.service.ScheduleJobService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 */
@Slf4j
public class SpringBeanMethodInvokeTask extends AbstractTask {

    private static final String PATTERN = "^([\\w_]*)\\.([\\w_]*?)\\((.*?)\\)$";

    @Autowired
    private ScheduleJobService scheduleJobService;

    @Autowired
    protected LogService logService;


    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        JobDataMap mergedJobDataMap = context.getMergedJobDataMap();
        ScheduleJob jobParam = (ScheduleJob) mergedJobDataMap.get(ScheduleJob.class.getName());
        String invokeTarget = jobParam.getInvokeTarget();
        //删除日志
        Log logInfo=new Log();
        logInfo.setParam("任务名称："+jobParam.getJobName()+"，调用方法："+jobParam.getInvokeTarget()).setMsg("执行成功").setCreatorName("system");
        logInfo.setLogType(LogType.success).setBusType(jobParam.getJobName()+ "[自动]").setBusKey(null).setBusId(jobParam.getId());
        ScheduleJob jobDb = scheduleJobService.getById(jobParam.getId());
        try {
            scheduleJobService.checkJob(jobDb, "自动执行");
            Pattern pattern = Pattern.compile(PATTERN);
            Matcher matcher = pattern.matcher(invokeTarget);

            matcher.find();
            String beanName = matcher.group(1);
            String methodName = matcher.group(2);

            //参数字符串
            String paramsStr = matcher.group(3);

            resolveParameters(paramsStr);

            Object[] params = getParameters();
            Class[] paramClasses = getParametersType();

            Object bean = SpringUtils.getBean(beanName);

            Method method = bean.getClass().getMethod(methodName, paramClasses);

            //更新任务状态
            scheduleJobService.updateJobStatusExecution(Arrays.asList(jobDb), GlobalConsts.JobStatusExecution.EXEC);

            Object objRet = method.invoke(bean, params);
            String retMsg = "该任务未返回任何信息，请查看系统日志";
            logInfo.setLogType(LogType.success);
            if(UtilCommon.strIsNull(retMsg)) retMsg = "执行成功，该任务未返回任何信息，请查看系统日志";
            if (objRet != null) {
                if (objRet instanceof RestResult) {
                    RestResult restResult = (RestResult) objRet;
                    if (!restResult.isSuccess()) {
                        logInfo.setLogType(LogType.error);
                    }
                    BusinessException.throwErrorIf(!restResult.isSuccess(),restResult.getMsg());
                    retMsg = restResult.getMsg();
                } else {
                    retMsg = objRet+"";
                }
            }
            logInfo.setMsg(retMsg);

            //保存日志，更新任务状态
            Date dateNow = DateUtils.now();
            jobDb = scheduleJobService.getById(jobParam.getId());
            jobDb.setLastDate(dateNow).setLastStatus("1").setLastRemark(logInfo.getMsg()).setLastSuccessDate(dateNow).setNextFireTime(context.getNextFireTime());
            logService.save(logInfo);
            scheduleJobService.updateById(jobDb);

            //推送消息给运营管理员 和管理员
            CommonService.pushMessageRole("定时任务执行成功:"+jobDb.getJobName(), logInfo.getMsg(), "admin_yy,admin");
            //更新任务状态
            scheduleJobService.updateJobStatusExecution(Arrays.asList(jobDb), GlobalConsts.JobStatusExecution.NOT_EXEC);
        } catch (Exception e) {
            String timeMillis=System.currentTimeMillis()+"";
            String errorKey = "SpringBeanMethodInvokeTask.error."+jobDb.getJobName()+"."+timeMillis;
            log.error(errorKey,e);

            String traceMsg = UtilJavax.getStackTrace(e);
            if (traceMsg.length() > 300) traceMsg= traceMsg.substring(300);
            //保存日志，更新任务状态
            logInfo.setLogType(LogType.error).setMsg("执行失败"+",日志搜索标识，"+errorKey+"，异常信息："+ traceMsg);

            jobDb = scheduleJobService.getById(jobParam.getId());
            jobDb.setLastDate(DateUtils.now()).setLastStatus("0").setLastRemark(logInfo.getMsg())
            .setNextFireTime(context.getNextFireTime());

            //
            jobDb.setStatusExecution(GlobalConsts.JobStatusExecution.NOT_EXEC).setStatusExecutionDate(DateUtils.now());

            logService.save(logInfo);
            scheduleJobService.updateById(jobDb);

            //推送消息给运营管理员 和管理员
            CommonService.pushMessageRole("定时任务执行失败:"+jobDb.getJobName(), traceMsg, "admin_yy,admin");
            throw new JobExecutionException(e);
        }
    }

    public static boolean checkValidation(String invokeTarget) {
        Pattern pattern = Pattern.compile(PATTERN);
        Matcher matcher = pattern.matcher(invokeTarget);

        try {
            return matcher.matches() && SpringUtils.getBean(matcher.group(1)) != null;

        } catch (NoSuchBeanDefinitionException | NullPointerException e) {
            log.error("调用目标字符串无效", e);
            throw new BusinessException("调用目标字符串无效", e);
//            return false;
        }
    }
}
